package edu.nf.vrs.vaccination.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import com.github.pagehelper.PageInfo;
import edu.nf.vrs.vaccination.dao.InoculatePeriodDao;
import edu.nf.vrs.vaccination.dao.NeedleNumDao;
import edu.nf.vrs.vaccination.dto.InoculatePeriodDTO;
import edu.nf.vrs.vaccination.dto.NeedleNumDTO;
import edu.nf.vrs.vaccination.dto.NeedleNumPageDTO;
import edu.nf.vrs.vaccination.entity.InoculatePeriod;
import edu.nf.vrs.vaccination.entity.NeedleNum;
import edu.nf.vrs.vaccination.exception.NeedleNumException;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.transaction.annotation.Transactional;
import java.time.Duration;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * Author: @Wai
 * Date: 2022-3-30
 */
@DubboService(interfaceClass = NeedleNumService.class, version = "1.0.0")
@Transactional(rollbackFor = RuntimeException.class)
@Slf4j
public class NeedleNumServiceImpl implements NeedleNumService {

    @Autowired
    private InoculatePeriodDao periodDao;
    @Autowired
    private NeedleNumDao needleNumDao;
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    private static final String NEEDLE_NUM_PREFIX = "needleNum:";
    private static final String PERIOD_KEY_PREFIX = "period:";


    @Override
    public void addNeedleNum(NeedleNumDTO needleNumDto) {
        if (checkNeedleNum(needleNumDto)) {
            log.info("重复添加{}", needleNumDto);
            throw new NeedleNumException("不可重复添加！");
        }
        NeedleNum needleNum = BeanUtil.copyProperties(needleNumDto, NeedleNum.class);
        List<InoculatePeriod> periods = BeanUtil.copyToList(needleNumDto.getPeriods(), InoculatePeriod.class);
        int total = periods.stream().filter(period -> Objects.nonNull(period.getVaccineTotal()))
                .mapToInt(InoculatePeriod::getVaccineTotal).sum();
        needleNum.setVaccineTotal(total);
        needleNum.setVaccineOver(total);
        periods.forEach(inoculatePeriod -> inoculatePeriod.setNeedleNumId(needleNum.getNid()));
        needleNumDao.saveNeedleNum(needleNum);
        periodDao.saveInoculatePeriod(periods);
    }

    @Override
    public void decrTotal(Integer IpId, Integer needleNumId) {
        if (periodDao.decrInoculatePeriod(IpId)==0) {
            throw new NeedleNumException("该时段预约已满！");
        }
        needleNumDao.decrTotal(needleNumId);
    }

    @Override
    public NeedleNumPageDTO listNeedleNum(NeedleNumDTO dto, Integer pageNum, Integer pageSize) {
        NeedleNum needleNum = BeanUtil.copyProperties(dto, NeedleNum.class);
        List<NeedleNum> needleNums = needleNumDao.listNeedleNum(needleNum, pageNum, pageSize);
        PageInfo pageInfo = new PageInfo(needleNums);
        return BeanUtil.copyProperties(pageInfo,NeedleNumPageDTO.class);
    }

    @Override
    public List<InoculatePeriodDTO> listPeriodByNeedleNumId(Integer needleNumId) {
        if (!redisTemplate.hasKey(NEEDLE_NUM_PREFIX + needleNumId)) {
            List<InoculatePeriod> periods = periodDao.listInoculatePeriod(needleNumId);
            redisTemplate.opsForValue().set(NEEDLE_NUM_PREFIX + needleNumId, periods, Duration.ofHours(12));
        }
        List<InoculatePeriod> periods = (List<InoculatePeriod>) redisTemplate.opsForValue().get(NEEDLE_NUM_PREFIX + needleNumId);
        Date date = needleNumDao.listNeedleNumById(new Integer[]{needleNumId}).get(0).getInoculateDate();
        periods.stream().filter(period -> getExpTime(date,period.getPeriod())>0).forEach(period -> {
                if(!redisTemplate.hasKey(PERIOD_KEY_PREFIX+period.getIpId())) {
                    redisTemplate.opsForValue().set(PERIOD_KEY_PREFIX + period.getIpId(),
                            period.getVaccineTotal(),
                            TimeUnit.MILLISECONDS.toMinutes(getExpTime(date, period.getPeriod())), TimeUnit.MINUTES);
                }else {
                    period.setVaccineTotal((Integer) redisTemplate.opsForValue().get(PERIOD_KEY_PREFIX + period.getIpId()));
                }
        });
        periods = periods.stream().filter(period -> period.getVaccineTotal() != null)
                .collect(Collectors.toList());
        return BeanUtil.copyToList(periods, InoculatePeriodDTO.class);
    }


    /**
     * 检查是否已添加过该接种点当天的针次
     * 若已添加过则返回true，否则返回false
     *
     * @param needleNum
     * @return
     */
    private boolean checkNeedleNum(NeedleNumDTO needleNum) {
        NeedleNum check = new NeedleNum();
        check.setNeedleNum(needleNum.getNeedleNum());
        check.setInoculateDate(needleNum.getInoculateDate());
        check.setAddressId(needleNum.getVaccination().getVid());
        List<NeedleNum> needleNums = needleNumDao.listNeedleNum(check,0,1);
        if (needleNums != null) {
            return true;
        }
        return false;
    }

    private Long getExpTime(Date date,String period){
        String time = DateUtil.format(date,"yyyy-MM-dd") + " " + period.split("-")[1].trim();
        Date periodDate = DateUtil.parse(time);
        return periodDate.getTime() - new Date().getTime();
    }

}
